package com.mfp.java.testYou.core.servlets;

import com.mfp.java.testYou.core.AppContext;
import com.mfp.java.testYou.core.utils.UrlUtils;
import com.mfp.java.testYou.db.model.CompletedTest;
import com.mfp.java.testYou.db.model.Question;
import com.mfp.java.testYou.db.model.TakenTest;
import com.mfp.java.testYou.db.model.TestManager;
import com.mfp.java.testYou.ui.mvc.AnswerQuestionPage;
import com.mfp.java.testYou.ui.mvc.DetailedResultPage;
import org.apache.log4j.Logger;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * This servlet will dispatch the user to the target site (answer question, or
 * view result)
 */
public class TakeTestServlet extends HttpServlet {

	private static final long serialVersionUID = -7735706862443746762L;
	private static final Logger log = Logger.getLogger(TakeTestServlet.class);
	// same value as in web.xml
	public static final String URL = "/testYou/takeTest.html";

	public static final String OPERATION = "operation";
	public static final String OPERATION_START_TEST = "startTest";
	public static final String OPERATION_ANSWER = "answer";
	public static final String OPERATION_FINISH_TEST = "finishTest";

	public static final String INPUT_TESTID = "testId";
	public static final String INPUT_ANSWER = "answer";
	public static final String INPUT_CURR_Q = "currQ";
	public static final String INPUT_NEXT_Q = "nextQ";

	public void doGet(HttpServletRequest req, HttpServletResponse resp) {
		doPost(req, resp);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) {
		if (OPERATION_START_TEST.equals(getOperation(request))) {
			createTest(request);
			String params = UrlUtils.makeParamsString(TakeTestServlet.OPERATION, TakeTestServlet.OPERATION_ANSWER);
			UrlUtils.forwardToTarget(request, response, TakeTestServlet.URL + params);
			return;
		}

		if (OPERATION_ANSWER.equals(getOperation(request))) {
			resolveAnswers(request);
			prepareAnswerPage(request);
			UrlUtils.forwardToTarget(request, response, AnswerQuestionPage.URL);
			return;
		}

		if (OPERATION_FINISH_TEST.equals(getOperation(request))) {
			resolveAnswers(request);
			finishTest(request);
			UrlUtils.forwardToTarget(request, response, DetailedResultPage.URL);
			return;
		}

		log.error("Unknown command: " + getOperation(request));
		String fromMenu = request.getParameter("fromMenu");

		request.getSession().setAttribute("fromMenu", fromMenu);
		UrlUtils.redirectToTarget(request, response, "/");

	}

	private void finishTest(HttpServletRequest req) {
		TestManager.finishTest(AppContext.getUserSession(req).getTakenTest());

		float res = AppContext.getUserSession(req).getTakenTest().getResult();
		String userName = AppContext.getUserSession(req).getUserName();
		Integer testId = AppContext.getUserSession(req).getTakenTest().getTestId();
		String testName = AppContext.getDAO().getTest(testId).getTitle();

		CompletedTest ct = new CompletedTest();

		ct.setDate(new Date());
		ct.setResult(res);
		ct.setTitle(testName);
		ct.setUserName(userName);

		try {
			AppContext.getDAO().addCompletedTest(ct);

			AppContext.getUserSession(req).setTakenTest(null);

		} catch (SQLException e) {
			log.error(e.getClass().getName() + " " + e.getMessage());
		}
	}

	private void resolveAnswers(HttpServletRequest request) {
		try {
			String sCurQ = request.getParameter(INPUT_CURR_Q);
			Integer currQ = new Integer(sCurQ);
			List<Integer> list = getAnswers(request);
			TestManager.setAnswer(AppContext.getUserSession(request).getTakenTest(), currQ, list);
		} catch (IllegalArgumentException e) {
			log.error(e.getClass().getName() + " " + e.getMessage());
		} catch (NullPointerException e) {
			log.error(e.getClass().getName() + " " + e.getMessage());
		}
	}

	private List<Integer> getAnswers(HttpServletRequest request) {
		@SuppressWarnings("unchecked")
		Map<String, String[]> map = request.getParameterMap();

		List<Integer> ids = new LinkedList<Integer>();

		for (String key : map.keySet()) {
			if (key.startsWith(INPUT_ANSWER)) {
				String sid = key.replace(INPUT_ANSWER, "");
				Integer iid = new Integer(sid);
				ids.add(iid);
			}
		}

		return ids;
	}

	private String getOperation(HttpServletRequest request) {
		return request.getParameter(OPERATION);
	}

	private void createTest(HttpServletRequest request) {
		String testId = request.getParameter(INPUT_TESTID);
		Integer testIdInt = new Integer(testId);
		TakenTest tt = TestManager.createTest(testIdInt);
		AppContext.getUserSession(request).setTakenTest(tt);
	}

	private void prepareAnswerPage(HttpServletRequest request) {

		String ans = request.getParameter(INPUT_NEXT_Q);

		Integer answerNo = null;
		try {
			answerNo = new Integer(ans);
		} catch (RuntimeException e) {
			log.debug("No question number found. Setting first question");
			log.debug("Number:" + ans);
			answerNo = 0;
		}

		TakenTest tt = AppContext.getUserSession(request).getTakenTest();

		log.debug("Preparing test for tt: " + tt);

		Integer qId = tt.getAnswers().get(answerNo).getQuestionId();

		Question q = AppContext.getDAO().getQuestion(qId);

		request.setAttribute(AnswerQuestionPage.ATTR_QUESTION_NO, answerNo);
		request.setAttribute(AnswerQuestionPage.ATTR_CURR_QUESTION, q);
		request.setAttribute(AnswerQuestionPage.ATTR_ALLOW_HINTS, tt.isAllowHints());
	}

}
